import os
from concurrent.futures import ThreadPoolExecutor, wait, as_completed
from urllib import request, parse
import base64
import json
try:
    from .cvio import cvio
    from .updateService import updateIndex
    from .running_faster import Runner
except:
    from cvio import cvio
    from updateService import updateIndex
    from running_faster import Runner
from copy import deepcopy
import numpy as np
from collections import Counter


_labelme_format = {
    "imagePath": "",
    "imageHeight": 0,
    "imageWidth": 0,
    "imageData": None,
    "lineColor": [
        0,
        255,
        0,
        128
    ],
    "fillColor": [
        255,
        0,
        0,
        128
    ],
    "flags": {},
    "shapes": [
        # {
        #     "line_color":None,
        #     "fill_color":None,
        #     "label":"",
        #     "shape_type":"polygon",
        #     "flags":{},
        #     "points":[],
        # }
    ]
}


def gen_mask_to(saveroot, imgpath, data, filter_daiding=False, with_score=False):
    if not os.path.exists(saveroot):
        os.makedirs(saveroot)
    boxInfo = data['boxInfo']
    imageInfo = data['imageInfo']
    width = imageInfo['width']
    height = imageInfo['height']
    Mask = deepcopy(_labelme_format)
    Mask['imagePath'] = os.path.basename(imgpath)
    Mask['imageWidth'] = width
    Mask['imageHeight'] = height
    Shape = {
        "line_color": None,
        "fill_color": None,
        "label": "",
        "shape_type": "polygon",
        "flags": {},
        "points": [],
    }
    layers = []
    labels = []
    for sku in boxInfo:
        if filter_daiding and 'daiding' in sku['skuName']:
            continue
        shape = deepcopy(Shape)
        label = sku['skuName']#.split('-')[0]
        labels.append(label)
        if 'layer' in sku and sku['layer'] != '':
            layer = int(sku['layer'])
            layers.append(layer)
            shape['layer'] = layer
        if with_score:
            score = sku['score']
            label = '%s_%.2f' % (label, float(score))
        shape['label'] = label
        shape['points'] = [[int(sku['location']['xmin'] * width), int(sku['location']['ymin'] * height)],
                           [int(sku['location']['xmin'] * width),
                            int(sku['location']['ymax'] * height)],
                           [int(sku['location']['xmax'] * width),
                            int(sku['location']['ymax'] * height)],
                           [int(sku['location']['xmax'] * width), int(sku['location']['ymin'] * height)]]
        if 'index' in sku:
            shape['index'] = sku['index']
        Mask['shapes'].append(shape)
    if layers and filter_daiding:
        Mask['shapes'] = [Mask['shapes'][i]
                          for i in np.argsort(np.array(layers))]
    else:
        Mask['shapes'] = [Mask['shapes'][i]
                          for i in np.argsort(np.array(labels))]
    cvio.write_ann(Mask, os.path.join(
        saveroot, os.path.splitext(imgpath)[0]+'.json'))


def encodeImg(imgName):
    with open(imgName, 'rb') as f:
        data = f.read()
        encodestr = base64.b64encode(data)
    return encodestr


def visitIndex(url, name=''):
    data = bytes(parse.urlencode({}), encoding='utf-8')
    req = request.Request('%s/visitIndex' % url, data=data)
    res = request.urlopen(req).read()
    res = bytes.decode(res)
    res = json.loads(res)
    if not res['status']:
        print('访问指纹数据库失败!')
        return
    data = res['data']
    print('*'*10)
    print('已学习库')
    learned = data['learned']
    print(list(learned.keys()))
    for k1, v1 in learned.items():
        if 'current' not in v1:
            continue
        print('当前路由', k1)
        n = 0
        c = 0
        for k2, v2 in v1.items():
            if 'header' in k2:
                for k3, v3 in v2.items():
                    print(k3, v3)
                continue
            if 'data' in k2:
                n = v2['shape'][0]
            if 'count' in k2:
                c = len(v2)
                if name in v2:
                    print('%s存在%d条指纹数据' % (name, v2[name]))
        print('%d款SKU, %d条指纹数据' % (c, n)) 

    print('*'*10)
    print('新品库')
    unlearned = data['unlearned']
    print(list(unlearned.keys()))
    for k1, v1 in unlearned.items():
        if 'current' not in v1:
            continue
        print('当前路由', k1)
        n = 0
        c = 0
        for k2, v2 in v1.items():
            if 'header' in k2:
                for k3, v3 in v2.items():
                    print(k3, v3)
                continue
            if 'data' in k2:
                n = v2['shape'][0]
            if 'count' in k2:
                c = len(v2)
                if name in v2:
                    print('%s存在%d条指纹数据' % (name, v2[name]))
        print('%d款SKU, %d条指纹数据' % (c, n))

    print('*'*10)
    print('\n')
    print('*'*10)
    memory = data['memory']
    print('当前显存 已学习')
    learned_ind_map = memory['learned_ind_map']
    learned_ind_map = dict(Counter(list(learned_ind_map.values())))
    print('%d款SKU, %d条指纹数据' %
          (len(learned_ind_map), sum(list(learned_ind_map.values()))))
    if name in learned_ind_map:
        c = learned_ind_map[name]
        print('%s存在%d条指纹数据' % (name, c))

    print('*'*10)
    print('当前显存 新品')
    unlearned_ind_map = memory['unlearned_ind_map']
    unlearned_ind_map = dict(Counter(list(unlearned_ind_map.values())))
    print('%d款SKU, %d条指纹数据' %
          (len(unlearned_ind_map), sum(list(unlearned_ind_map.values()))))
    if name in unlearned_ind_map:
        c = unlearned_ind_map[name]
        print('%s存在%d条指纹数据' % (name, c))

    print('*'*10)

def testHttp(url, src, dst, detRoute='layerDet', uroute='10104', tenantId='bottle', 
             lthr=None, uthr=None, ltopk=None, utopk=None, 
             filter_daiding=True, with_score=True, worker='thread', num_workers=8):
    if not os.path.exists(dst):
        os.makedirs(dst)
    data = dict()
    updateFlag = False
    if lthr not in (None, ''):
        data.update({"lthr": lthr})
        updateFlag = True
    if ltopk not in (None, ''):
        data.update({"ltopk": ltopk})
        updateFlag = True
    if uthr not in (None, ''):
        data.update({"uthr": uthr})
        updateFlag = True
    if utopk not in (None, ''):
        data.update({"utopk": utopk})
        updateFlag = True
    if uroute not in (None, ''):
        data.update({'uroute': uroute})
        updateFlag = True
    if updateFlag:
        try:
            res = updateIndex(url, data)
            if not res['status']:
                print('更新参数失败.')
        except:
            pass

    imglist = cvio.load_image_list(src)
    detUrl = '%s/%s' % (url, detRoute)

    tbar = enumerate(imglist, 1)
    n = len(imglist)
    runner = Runner()
    #runner = ThreadPoolExecutor(num_workers)
    #pools = []
    for i, impath in tbar:
        # print('Preload task [%d/%d] %s' % (i, n, impath))
        runner.append(detect_one_image, (i, n, detUrl, tenantId, impath, dst, filter_daiding, with_score))
        #p = runner.submit(detect_one_image, i, n, detUrl, tenantId, impath, dst, filter_daiding, with_score)
        #pools.append(p)

    runner.run(mode=worker, num_workers=num_workers)
    # wait(pools)
    #for p in as_completed(pools):
    #    try:
    #        p.result()
    #    except Exception as e:
    #        print(e)
    #        runner.shutdown(wait=True)
        

    # headers = dict(tenantId=parse.quote(tenantId))

    # for i, impath in tbar:
    #     print(i, os.path.basename(impath))
    #     try:
    #         encodestr = encodeImg(impath)
    #         data = {'base64Data': encodestr, 'cabinetType': 0}
    #         data = parse.urlencode(data).encode('utf-8')
    #         req = request.Request('%s/%s' % (url, detRoute), headers=headers, data=data)
    #         page = request.urlopen(req).read()
    #         page = bytes.decode(page)
    #         page = json.loads(page)
    #         if not 'data' in page: 
    #             print('无识别结果返回.')
    #             continue
    #         print(page['data']['skuStat'])  #
    #         f = os.path.basename(impath)
    #         gen_mask_to(
    #             dst, f, page['data'], filter_daiding=filter_daiding, with_score=with_score)
    #     except Exception as e:
    #         print(e, impath)

def detect_one_image(i, n, url, tenantId, impath, dst, filter_daiding, with_score):
    headers = dict(tenantId=parse.quote(tenantId))
    print('[%d/%d]' % (i, n), os.path.basename(impath))
    
    encodestr = encodeImg(impath)
    data = {'base64Data': encodestr, 'cabinetType': 0}
    data = parse.urlencode(data).encode('utf-8')
    req = request.Request(url, headers=headers, data=data)
    page = request.urlopen(req).read()
    page = bytes.decode(page)
    page = json.loads(page)
    print(page['data']['skuStat'])  #
    f = os.path.basename(impath)
    gen_mask_to(
        dst, f, page['data'], filter_daiding=filter_daiding, with_score=with_score) 


if __name__ == '__main__':
    url = 'http://172.16.1.186:9091/detService'
    src = '/data/hjzhen/data/yl_sku_data/my_demo/test'
    dst = src + '/autolabel'
    testHttp(url, src, dst)
